
#include <mex.h>
#include <string.h>
#include <math.h>

#include "shm_array.h"

static void usage_error (){
	mexErrMsgTxt("write_shmmat('var');\n"
	              "write_shmmat var;\n"
	              "write_shmmat('key string', var);\n");
}

void
mexFunction (int ml, mxArray *pl[], int nr, mxArray const *pr[])
{
	int i;
	mxArray const *mx;
	char *key;
	struct shm_array size, *shm;

	if (nr > 2)
		usage_error();

	else if (nr == 1){
		if (!mxIsChar(pr[0])) usage_error();
		key = mxArrayToString (pr[0]);
		mx = mexGetVariable ("caller", key);
	}
	else {
		if (!mxIsChar(pr[0])) usage_error();
		key = mxArrayToString (pr[0]);
		mx = pr[1];
	}

	if ((size.ndims = mxGetNumberOfDimensions(mx)) > MAX_SHMMAT_DIMS){
		char msg[1024];
		sprintf (msg, "ERROR: MAX_SHMMAT_DIMS = %d", MAX_SHMMAT_DIMS);
		mexErrMsgTxt (msg);
	}

	for (i = 0; i < mxGetNumberOfDimensions(mx); ++i){
		size.dims[i] = mxGetDimensions(mx)[i];
	}

	switch (mxGetClassID(mx))
	{
		case mxCHAR_CLASS: size.type = shm_array_char; break;
		case mxINT32_CLASS: size.type = shm_array_int32; break;
		case mxINT64_CLASS: size.type = shm_array_int32; break;
		case mxSINGLE_CLASS:
			if (mxIsComplex (mx))
				size.type = shm_array_cplxf;
			else
				size.type = shm_array_float;
			break;
		case mxDOUBLE_CLASS:
			if (mxIsComplex (mx))
				size.type = shm_array_cplxd;
			else
				size.type = shm_array_double;
			break;

		default:{
			char msg[1024];
			sprintf (msg, "ERROR: Unsupported array type: %s %s",
			            (mxIsComplex(mx) ? "complex" : "real"), 
			            mxGetClassName(mx));
			mexErrMsgTxt (msg);
		}
	}

	if (make_shm_array (key, &size, &shm)){
		mexErrMsgTxt("ERROR");
	}

	int n = 1;
	for (i = 0; i < shm->ndims; ++i)
		n *= shm->dims[i];

	mexPrintf("WRITING N=%d\n", n);

	switch (mxGetClassID(mx))
	{
		case mxCHAR_CLASS:
		case mxINT32_CLASS:
		case mxINT64_CLASS:
			memcpy (shm->data.s, mxGetData (mx), n*shm_type_sizes[shm->type]);
			break;	

		case mxSINGLE_CLASS:
			if (mxIsComplex (mx)){
				for (i = 0; i < n; ++i){
					shm->data.c[i].real = ((float*)mxGetData(mx))[i];
					shm->data.c[i].imag = ((float*)mxGetImagData(mx))[i];
				}
			}
			else{
				memcpy (shm->data.s, mxGetData (mx), n*shm_type_sizes[shm->type]);
			}
			break;

		case mxDOUBLE_CLASS:
			if (mxIsComplex (mx)){
				int nans = 0;
				for (i = 0; i < n; ++i){
					shm->data.z[i].real = mxGetPr(mx)[i];
					shm->data.z[i].imag = mxGetPi(mx)[i];
					if (isnan(shm->data.z[i].real)
					    || isnan(shm->data.z[i].imag))
						++nans;
				}
				mexPrintf("NANS=%d\n", nans);
			}
			else{
				memcpy (shm->data.s, mxGetData (mx), n*shm_type_sizes[shm->type]);
			}
	}

	put_shm_array (key, shm);
	mxFree (key);
}
